﻿/* 
    Simple Power Option - Is the program to configure Power settings for MS Windows 7
    Copyright (C) 2011  Alexey Egorov <Computer.Pers AT gmail.com>

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;
using System.ComponentModel;
namespace WinAPI
{
    public static class NativeMethods
    {

        //const string GUID_PROCESSOR_SETTINGS_SUBGROUP="54533251-82be-4824-96c1-47b60b740d00";

        /// <summary>Gets the Guid relating to the currently active power scheme.
        /// </summary>
        /// <param name="rootPowerKey">Reserved for future use, this must be set to IntPtr.Zero</param>
        /// <param name="activePolicy">Returns a Guid referring to the currently active power scheme.</param>
        /// <remarks>http://msdn.microsoft.com/en-us/library/aa372731(VS.85).aspx
        /// </remarks>
        /// <returns>Returns ERROR_SUCCESS (zero) if the call was successful, 
        /// and a non-zero value if the call failed.</returns>
        [DllImport("powrprof.dll")]
        internal static extern uint PowerGetActiveScheme(
         IntPtr userRootPowerKey,
         ref IntPtr activePolicy);

        /// <summary>
        /// Sets the AC value index of the specified power setting.
        /// </summary>
        /// <param name="rootPowerKey">This parameter is reserved for 
        /// future use and must be set to "IntPtr.Zero".</param>
        /// <param name="schemeGuid">The identifier of the power scheme.</param>
        /// <param name="subGroupOfPowerSettingsGuid">The subgroup 
        /// of power settings. </param>
        /// <param name="PowerSettingGuid">The identifier of the power setting.
        /// </param>
        /// <param name="AcValueIndex">The AC value index.</param>
        /// <returns>Returns ERROR_SUCCESS (zero) if the call was 
        /// successful, and a non-zero value if the call failed.</returns>
        /// <remarks>http://msdn.microsoft.com/en-us/library/aa372765(VS.85).aspx
        /// </remarks>
       /* [DllImport("powrprof.dll")]
        internal static extern uint PowerWriteACValueIndex(
         [In] IntPtr rootPowerKey,
         [In] ref Guid schemeGuid,
         [In] ref Guid subGroupOfPowerSettingsGuid,
         [In] ref Guid PowerSettingGuid,
         uint AcValueIndex);

        [DllImport("powrprof.dll")]
        internal static extern uint PowerWriteDCValueIndex(
         [In] IntPtr rootPowerKey,
         [In] ref Guid schemeGuid,
         [In] ref Guid subGroupOfPowerSettingsGuid,
         [In] ref Guid PowerSettingGuid,
         uint DcValueIndex);*/

        /*[DllImport("powrprof.dll")]
        internal static extern UInt32 PowerReadFriendlyName(
         [In] IntPtr RootPowerKey,
         [In] IntPtr SchemeGuid,
         [In] IntPtr SubGroupOfPowerSettingGuid,
         [In] IntPtr PowerSettingGuid,
         [Out] IntPtr Buffer,
         ref UInt32 BufferSize);*/

        [DllImport("powrprof.dll")]
        internal static extern UInt32 PowerReadFriendlyName(
        IntPtr RootPowerKey,
        IntPtr SchemeGuid,
        IntPtr SubGroupOfPowerSettingGuid,
        IntPtr PowerSettingGuid,
        IntPtr Buffer,
        ref UInt32 BufferSize);

        [DllImport("powrprof.dll")]
        internal static extern UInt32 PowerReadFriendlyName(
            IntPtr RootPowerKey,
            ref Guid SchemeGuid,
        IntPtr SubGroupOfPowerSettingGuid,
        IntPtr PowerSettingGuid,
        IntPtr Buffer,
        ref UInt32 BufferSize);

        [DllImport("powrprof.dll")]
        internal static extern UInt32 PowerReadACValue(
                    IntPtr RootPowerKey,
                    IntPtr SchemeGuid,
                    IntPtr SubGroupOfPowerSettingGuid,
                    IntPtr PowerSettingGuid,
                    ref IntPtr Type,
                    IntPtr Buffer,
                    ref UInt32 BufferSize);

        [DllImport("powrprof.dll")]
        internal static extern UInt32 PowerWriteACValueIndex(
                    IntPtr RootPowerKey,
                    IntPtr SchemeGuid,
                    IntPtr SubGroupOfPowerSettingsGuid,
                    IntPtr PowerSettingGuid,
                    [In] uint ACValueIndex
        );

        [DllImport("powrprof.dll")]
        internal static extern UInt32 PowerWriteDCValueIndex(
                    IntPtr RootPowerKey,
                    IntPtr SchemeGuid,
                    IntPtr SubGroupOfPowerSettingsGuid,
                    IntPtr PowerSettingGuid,
                    [In] uint DCValueIndex
        );

        [DllImport("powrprof.dll", EntryPoint = "PowerSetActiveScheme")]
        internal static extern UInt32 PowerSetActiveScheme(
            IntPtr UserRootPowerKey,
            IntPtr SchemeGuid
        );

        static public string PowerGetCurrentSchemeName()
        {
            string result = string.Empty;
            uint res;
            IntPtr curscheme = IntPtr.Zero;
            if (NativeMethods.PowerGetActiveScheme(IntPtr.Zero, ref curscheme) != 0)
            {
                result = "Error getting current scheme!";
            }
            else
            {
                uint buffSize = 0;
                res = NativeMethods.PowerReadFriendlyName(IntPtr.Zero, curscheme, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, ref buffSize);
                if (res == 0)
                {
                    IntPtr ptrName = Marshal.AllocHGlobal((int)buffSize);
                    res = NativeMethods.PowerReadFriendlyName(IntPtr.Zero, curscheme, IntPtr.Zero, IntPtr.Zero, ptrName, ref buffSize);
                    if (res == 0)
                    {
                        result = Marshal.PtrToStringUni(ptrName);
                    }
                    else
                    {
                        result = "Error code: " + res.ToString();
                    }
                    Marshal.FreeHGlobal(ptrName);
                }
            }
            return result;
        }
        static public int PowerGetCurrentSchemeProcessorMAX()
        {
            Guid GUID_PROCESSOR_SETTINGS_SUBGROUP = new Guid("54533251-82be-4824-96c1-47b60b740d00");
            IntPtr ptrGUID_PROCESSOR_SETTINGS_SUBGROUP = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(Guid)));
            Marshal.StructureToPtr(GUID_PROCESSOR_SETTINGS_SUBGROUP, ptrGUID_PROCESSOR_SETTINGS_SUBGROUP, true);

            Guid GUID_PROCESSOR_SETTINGS_ACMAXVAL = new Guid("bc5038f7-23e0-4960-96da-33abaf5935ec");
            IntPtr ptrGUID_PROCESSOR_SETTINGS_ACMAXVAL = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(Guid)));
            Marshal.StructureToPtr(GUID_PROCESSOR_SETTINGS_ACMAXVAL, ptrGUID_PROCESSOR_SETTINGS_ACMAXVAL, true);


            int result = -1;
            uint res;
            IntPtr curscheme = IntPtr.Zero;
            if (NativeMethods.PowerGetActiveScheme(IntPtr.Zero, ref curscheme) != 0)
            {
                result = -2;
            }
            else
            {

                UInt32 size = 1024;
                IntPtr temp = Marshal.AllocHGlobal(1024);
                IntPtr type = IntPtr.Zero;

                res = PowerReadACValue(IntPtr.Zero, curscheme, ptrGUID_PROCESSOR_SETTINGS_SUBGROUP, ptrGUID_PROCESSOR_SETTINGS_ACMAXVAL, ref type, temp, ref size);

                Win32Exception ex = new Win32Exception(Convert.ToInt16(res));
                string errMsg = ex.Message;

                if (res == 0)
                {

                    result = Marshal.ReadInt32(temp);
                }
                else
                {
                    result = Convert.ToInt32(res);

                }

                Marshal.FreeHGlobal(temp);
            }

            return result;
        }
        static public int PowerSetCurrentSchemeProcessorMAX(int value)
        {
            Guid GUID_PROCESSOR_SETTINGS_SUBGROUP = new Guid("54533251-82be-4824-96c1-47b60b740d00");
            IntPtr ptrGUID_PROCESSOR_SETTINGS_SUBGROUP = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(Guid)));
            Marshal.StructureToPtr(GUID_PROCESSOR_SETTINGS_SUBGROUP, ptrGUID_PROCESSOR_SETTINGS_SUBGROUP, true);

            Guid GUID_PROCESSOR_SETTINGS_ACMAXVAL = new Guid("bc5038f7-23e0-4960-96da-33abaf5935ec");
            IntPtr ptrGUID_PROCESSOR_SETTINGS_ACMAXVAL = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(Guid)));
            Marshal.StructureToPtr(GUID_PROCESSOR_SETTINGS_ACMAXVAL, ptrGUID_PROCESSOR_SETTINGS_ACMAXVAL, true);

            Guid GUID_PROCESSOR_SETTINGS_ACMINVAL = new Guid("893dee8e-2bef-41e0-89c6-b55d0929964c");
            IntPtr ptrGUID_PROCESSOR_SETTINGS_ACMINVAL = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(Guid)));
            Marshal.StructureToPtr(GUID_PROCESSOR_SETTINGS_ACMINVAL, ptrGUID_PROCESSOR_SETTINGS_ACMINVAL, true);

            int ProcessorTrheshhold = 5; // Разница между Минимальной и Максимальной мощностью процессора в %
            IntPtr curscheme = IntPtr.Zero;

            int result = Convert.ToInt32(NativeMethods.PowerGetActiveScheme(IntPtr.Zero, ref curscheme));
            if (result == 0)
            {
                result += Convert.ToInt32(NativeMethods.PowerWriteACValueIndex(IntPtr.Zero, curscheme, ptrGUID_PROCESSOR_SETTINGS_SUBGROUP, ptrGUID_PROCESSOR_SETTINGS_ACMINVAL, Convert.ToUInt32(value - ProcessorTrheshhold)));
                result += Convert.ToInt32(NativeMethods.PowerWriteACValueIndex(IntPtr.Zero, curscheme, ptrGUID_PROCESSOR_SETTINGS_SUBGROUP, ptrGUID_PROCESSOR_SETTINGS_ACMAXVAL, Convert.ToUInt32(value)));
                result += Convert.ToInt32(NativeMethods.PowerWriteDCValueIndex(IntPtr.Zero, curscheme, ptrGUID_PROCESSOR_SETTINGS_SUBGROUP, ptrGUID_PROCESSOR_SETTINGS_ACMINVAL, Convert.ToUInt32(value - ProcessorTrheshhold)));
                result += Convert.ToInt32(NativeMethods.PowerWriteDCValueIndex(IntPtr.Zero, curscheme, ptrGUID_PROCESSOR_SETTINGS_SUBGROUP, ptrGUID_PROCESSOR_SETTINGS_ACMAXVAL, Convert.ToUInt32(value)));
            };
            return result;

        }
        static public int PowerGetCurrentSchemeBrightness()
        {
            Guid GUID_VIDEO_SETTINGS_SUBGROUP = new Guid("7516b95f-f776-4464-8c53-06167f40cc99");
            IntPtr ptrGUID_VIDEO_SETTINGS_SUBGROUP = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(Guid)));
            Marshal.StructureToPtr(GUID_VIDEO_SETTINGS_SUBGROUP, ptrGUID_VIDEO_SETTINGS_SUBGROUP, true);

            Guid GUID_DISPLAY_BRIGHTNESS = new Guid("aded5e82-b909-4619-9949-f5d71dac0bcb");
            IntPtr ptrGUID_DISPLAY_BRIGHTNESS = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(Guid)));
            Marshal.StructureToPtr(GUID_DISPLAY_BRIGHTNESS, ptrGUID_DISPLAY_BRIGHTNESS, true);

            int result = -1;
            uint res;
            IntPtr curscheme = IntPtr.Zero;
            if (NativeMethods.PowerGetActiveScheme(IntPtr.Zero, ref curscheme) != 0)
            {
                result = -2;
            }
            else
            {

                UInt32 size = 1024;
                IntPtr temp = Marshal.AllocHGlobal(1024);
                IntPtr type = IntPtr.Zero;

                res = PowerReadACValue(IntPtr.Zero, curscheme, ptrGUID_VIDEO_SETTINGS_SUBGROUP, ptrGUID_DISPLAY_BRIGHTNESS, ref type, temp, ref size);

                Win32Exception ex = new Win32Exception(Convert.ToInt16(res));
                string errMsg = ex.Message;

                if (res == 0)
                {

                    result = Marshal.ReadInt32(temp);
                }
                else
                {
                    result = Convert.ToInt32(res);

                }

                Marshal.FreeHGlobal(temp);
            }

            return result;
        }
        static public int PowerSetCurrentSchemeBrightness(int value)
        {
            Guid GUID_VIDEO_SETTINGS_SUBGROUP = new Guid("7516b95f-f776-4464-8c53-06167f40cc99");
            IntPtr ptrGUID_VIDEO_SETTINGS_SUBGROUP = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(Guid)));
            Marshal.StructureToPtr(GUID_VIDEO_SETTINGS_SUBGROUP, ptrGUID_VIDEO_SETTINGS_SUBGROUP, true);

            Guid GUID_DISPLAY_BRIGHTNESS = new Guid("aded5e82-b909-4619-9949-f5d71dac0bcb");
            IntPtr ptrGUID_DISPLAY_BRIGHTNESS = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(Guid)));
            Marshal.StructureToPtr(GUID_DISPLAY_BRIGHTNESS, ptrGUID_DISPLAY_BRIGHTNESS, true);
            IntPtr curscheme = IntPtr.Zero;
            int result = Convert.ToInt32(NativeMethods.PowerGetActiveScheme(IntPtr.Zero, ref curscheme));

            if (result == 0)
            {
                result += Convert.ToInt32(NativeMethods.PowerWriteACValueIndex(IntPtr.Zero, curscheme, ptrGUID_VIDEO_SETTINGS_SUBGROUP, ptrGUID_DISPLAY_BRIGHTNESS, Convert.ToUInt32(value)));
                result += Convert.ToInt32(NativeMethods.PowerWriteDCValueIndex(IntPtr.Zero, curscheme, ptrGUID_VIDEO_SETTINGS_SUBGROUP, ptrGUID_DISPLAY_BRIGHTNESS, Convert.ToUInt32(value)));
            }
            return result;

        }
        static public Boolean PowerAllpyChanges()
        {
            Boolean result = false;
            IntPtr curscheme = IntPtr.Zero;
            if (NativeMethods.PowerGetActiveScheme(IntPtr.Zero, ref curscheme) == 0)
            {
                if (PowerSetActiveScheme(IntPtr.Zero, curscheme) == 0)
                {
                    result = true;
                }
            }
            else
            {
                result = false;
            }
            return result;
        }
    }
    
}
